cmake_minimum_required(VERSION 3.10)

include(config.cmake OPTIONAL)

#----------------------- 环境参数 ----------------------
set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
set(PROJECT_ROOT_PARENT ${PROJECT_ROOT}/..)
file(RELATIVE_PATH PROJECT_ROOT_NAME ${PROJECT_ROOT_PARENT}/.. ${PROJECT_ROOT_PARENT})

if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
	set(USERNAME $ENV{USERNAME})
else()
	set(USERNAME $ENV{USER})
endif()

#----------------------- 环境变量检测 ----------------------
if(NOT DEFINED ENV{JAVA_HOME})
    message(FATAL_ERROR "Must install JDK and define JAVA_HOME environment")    
endif()
if(NOT DEFINED ENV{ANDROID_PLATFORM})
    message(FATAL_ERROR "Must install Android Platform and define ANDROID_PLATFORM environment")    
endif()
if(NOT DEFINED ENV{ANDROID_BUILD_TOOLS})
    message(FATAL_ERROR "Must install Android Build Tools and define ANDROID_BUILD_TOOLS environment")    
endif()


#----------------------- 取默认参数宏 ----------------------
macro(set_default)
if("${${ARGV0}}" STREQUAL "")
	set(${ARGV0} $ENV{${ARGV0}})	
	if("${${ARGV0}}" STREQUAL "")	    
		set(${ARGV0} ${ARGV1} ${ARGV2} ${ARGV3} ${ARGV4} ${ARGV5} ${ARGV6})
	endif()
endif()
endmacro()

#----------------------- 配置参数 ----------------------
set_default(PROJECT_NAME ${PROJECT_ROOT_NAME})

set_default(JAVA_SRC_DIR ${PROJECT_ROOT}/src) #java 源码目录
set_default(JAVA_LIB_DIR ${PROJECT_ROOT}/libs) #java 库目录
set_default(ANDROID_RES_DIR ${PROJECT_ROOT}/res) # res目录
set_default(ANDROID_ASSETS_DIR ${PROJECT_ROOT}/assets) # assets目录
set_default(ANDROID_JNILIB_DIR ${PROJECT_ROOT}/jniLibs) # jniLibs目录
set_default(ANDROID_MANIFEST ${PROJECT_ROOT}/AndroidManifest.xml)  # AndroidManifest.xml
set_default(KEYSTORE ${PROJECT_ROOT}/keystore.jks)  # 签名密钥jks
set_default(KEYSTORE_PASSWORD 12345678)  # 签名密钥密码，建议通过环境变量KEYSTORE_PASSWORD传入

#----------------------- 版本号 ----------------------
set_default(BUILD_NUMBER 1)
set_default(VERSION_STRING 1.0.${BUILD_NUMBER})


#----------------------- 读manifest，得到包名 PACKAGE_NAME , 以目录分隔的包名 PACKAGE_DIR ----------------------
message("-- Reading AndroidManifest.xml ...")
file(READ ${ANDROID_MANIFEST} MANIFEST_DATA)
string(REGEX MATCH  "package=\"[A-Za-z0-9.]+" PACKAGE_NAME_EXP ${MANIFEST_DATA})
if( "${PACKAGE_NAME_EXP}" STREQUAL "")
	message(FATAL_ERROR "Must define package=xxx.xxx.xxx in AndroidManifest.xml" )
endif()
string(REPLACE  "package=\"" "" PACKAGE_NAME ${PACKAGE_NAME_EXP})
message("-- Package Name: " ${PACKAGE_NAME})
string(REPLACE  "." "/" PACKAGE_DIR ${PACKAGE_NAME})

string(REGEX MATCH  "android:name=\"[A-Za-z0-9.]+Activity" ACTIVITY_NAME_EXP ${MANIFEST_DATA})
if(NOT "${ACTIVITY_NAME_EXP}" STREQUAL "")
	string(REPLACE  "android:name=\"" "" ACTIVITY_NAME ${ACTIVITY_NAME_EXP})
endif()
message("-- Activity Name: " ${ACTIVITY_NAME})

#----------------------- 查找所有xml文件 ----------------------
file(GLOB_RECURSE ANDROID_RES_XMLS ${ANDROID_RES_DIR}/*.xml)

#----------------------- 查找所有assets文件 ----------------------
file(GLOB_RECURSE ANDROID_ASSETS_FILES ${ANDROID_ASSETS_DIR}/*)

#----------------------- 生成 resources.ap_ 和 R.java ----------------------
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/gen)
set(APK_ASSETS)
if(EXISTS ${ANDROID_ASSETS_DIR})
    set(APK_ASSETS -A ${ANDROID_ASSETS_DIR})
endif()
set(AAPT_VERSION_OPT --version-code ${BUILD_NUMBER} --version-name ${VERSION_STRING})
set(AAPT_BUILD_COMMAND $ENV{ANDROID_BUILD_TOOLS}/aapt p -f -m -M ${ANDROID_MANIFEST} ${AAPT_VERSION_OPT} -I $ENV{ANDROID_PLATFORM}/android.jar -S ${ANDROID_RES_DIR}  -F resources.ap_ -J gen ${APK_ASSETS})
add_custom_command(OUTPUT resources.ap_ gen/${PACKAGE_DIR}/R.java COMMENT "Compiling resources"  DEPENDS ${ANDROID_MANIFEST} ${ANDROID_RES_XMLS} ${ANDROID_ASSETS_FILES} COMMAND ${AAPT_BUILD_COMMAND})


#----------------------- 查找所有java文件，并生成文件列表java_srcs.lst 得到变量 JAVA_SRCS JAVA_CLASSES ----------------------

file(GLOB_RECURSE JAVA_SRCS_SET RELATIVE ${JAVA_SRC_DIR} ${JAVA_SRC_DIR}/*.java )
file(RELATIVE_PATH JAVA_SRCS_REL  ${CMAKE_BINARY_DIR} ${JAVA_SRC_DIR})
foreach(JAVA_FILE IN LISTS JAVA_SRCS_SET)
	string(REPLACE .java .class CLASS_FILE ${JAVA_FILE})
	list(APPEND JAVA_SRCS ${JAVA_SRCS_REL}/${JAVA_FILE})
	list(APPEND JAVA_CLASSES classes/${CLASS_FILE})
endforeach()
string(JOIN " " JAVA_SRCS_STR ${JAVA_SRCS})
file(WRITE ${CMAKE_BINARY_DIR}/java_srcs.lst ${JAVA_SRCS_STR})


#------------- 查找所有jar文件，并生成文件列表 classpath.lst(;分割) 和 jars.lst(一行一个) ----------------------

file(GLOB JAVA_LIBS RELATIVE ${CMAKE_BINARY_DIR} ${JAVA_LIB_DIR}/*.jar )
string(JOIN "\n" JAVA_LIBS_STR ${JAVA_LIBS})
file(WRITE ${CMAKE_BINARY_DIR}/jars.lst "${JAVA_LIBS_STR}")

list(INSERT JAVA_LIBS 0 $ENV{ANDROID_PLATFORM}/android.jar)
string(JOIN ";" JAVA_LIBS_STR ${JAVA_LIBS})
file(WRITE ${CMAKE_BINARY_DIR}/classpath.lst "${JAVA_LIBS_STR}")


#----------------------- 编译java代码，输出到classes目录 ----------------------

set(CMAKE_JAVA_COMPILE_FLAGS -encoding UTF-8)
add_custom_command(OUTPUT ${JAVA_CLASSES} COMMENT "Compiling java sources" DEPENDS gen/${PACKAGE_DIR}/R.java ${JAVA_SRCS} COMMAND javac ${CMAKE_JAVA_COMPILE_FLAGS} -cp @classpath.lst -d classes gen/${PACKAGE_DIR}/R.java @java_srcs.lst )


#----------------------- 生成jar文件，输出为classes.jar ----------------------

add_custom_command(OUTPUT classes.jar COMMENT "Create jar file" DEPENDS ${JAVA_CLASSES} COMMAND jar -cf classes.jar -C classes . )


#----------------------- 生成dex，输出为classes.dex ----------------------
if("$CMAKE_BUILD_TYPE" STREQUAL "Debug")
    set(DEX_OPT --debug)
else()
    set(DEX_OPT --release)
endif()
set(DEX_OPT ${DEX_OPT} --min-api 27)
add_custom_command(OUTPUT classes.dex COMMENT "Create dex file"  DEPENDS classes.jar COMMAND $ENV{ANDROID_BUILD_TOOLS}/d8 ${DEX_OPT} classes.jar @jars.lst )


#----------------------- 生成unsiged apk，输出为app_unaligned_unsigned.ap_ ----------------------
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
	set(CP copy /y)
else()
	set(CP cp -f)
endif()
if(EXISTS ${ANDROID_JNILIB_DIR})
file(GLOB_RECURSE JNILIB_SO_FILES ${ANDROID_JNILIB_DIR}/*.so)
add_custom_command(OUTPUT app_unaligned_unsigned.ap_ COMMENT "Pack unsigned apk" DEPENDS classes.dex ${JNILIB_SO_FILES} resources.ap_ COMMAND ${CP} resources.ap_ app_unaligned_unsigned.ap_ COMMAND jar -uf app_unaligned_unsigned.ap_ classes.dex COMMAND jar -uf app_unaligned_unsigned.ap_ -C ${ANDROID_JNILIB_DIR} .)
else()
add_custom_command(OUTPUT app_unaligned_unsigned.ap_ COMMENT "Pack unsigned apk" DEPENDS classes.dex resources.ap_ COMMAND ${CP} resources.ap_ app_unaligned_unsigned.ap_ COMMAND jar -uf app_unaligned_unsigned.ap_ classes.dex) 
endif()


#----------------------- 生成zipligned apk，输出为 app_aligned_unsigned.apk ----------------------
add_custom_command(OUTPUT app_aligned_unsigned.ap_ COMMENT "Zipalign apk"  DEPENDS app_unaligned_unsigned.ap_ COMMAND $ENV{ANDROID_BUILD_TOOLS}/zipalign -f -v 8 app_unaligned_unsigned.ap_ app_aligned_unsigned.ap_)

#-------------------- Sign APK 输出为 app.apk --------------------
add_custom_command(OUTPUT app.apk COMMENT "Sign app.apk"  DEPENDS app_aligned_unsigned.ap_ ${KEYSTORE} COMMAND $ENV{ANDROID_BUILD_TOOLS}/apksigner sign --ks ${KEYSTORE} --ks-pass pass:${KEYSTORE_PASSWORD} --in app_aligned_unsigned.ap_ --out app.apk)


project(${PROJECT_NAME} LANGUAGES Java)


add_custom_target(gen_R_java DEPENDS gen/${PACKAGE_DIR}/R.java)
add_custom_target(app_build ALL DEPENDS app.apk)

#-------------------- App Install --------------------
add_custom_target(app_install COMMENT "Install app.apk" DEPENDS ${APK} COMMAND adb install -r app.apk)

#-------------------- App Run --------------------
add_custom_target(app_run COMMENT "Start App" COMMAND adb shell am start ${PACKAGE_NAME}/${ACTIVITY_NAME})


